/*
	Copyright (c) 2010 <copyright holders>
	This source code is licensed under The MIT License,
	see the file LICENSE for details.
	*/

#ifndef LANDSCAPE_HPP
#define LANDSCAPE_HPP

#include <boost/property_tree/ptree_fwd.hpp>
#include <OGRE/OgreCommon.h>

#include "ForwardDecls.hpp"
#include "Spatial.hpp"

namespace Ogre {
    class TerrainSceneManager;
};

namespace spelprog2 {

/**
    Interface that provides the spatial information of the landscape from the perspective
    of the XZ ground plane.
    */
struct LandscapeSpatials {
    typedef boost::shared_ptr<LandscapeSpatials> Pointer;
    typedef std::list<sim::Int2d> PointList;

    virtual ~LandscapeSpatials() {}

    //! Gets the extents of the height map on the ground plane (x, y), which is really X-Z globally...
    virtual sim::Int2d getExtents() const = 0;

    //! Gets the altitude on a point on the ground plane. (Integer version.)
    virtual sim::Int getAltitude(const sim::Int2d & position) const = 0;
    //! Gets the altitude on a point on the ground plane. (Float version.)
    virtual Ogre::Real getAltitude(const Ogre::Vector2 & position) const = 0;

    //! Gets the inclination angle along a certain direction at a position. (Integer version.)
    virtual sim::Int getInclination(const sim::Int2d & position, const sim::Int2d & direction) const = 0;
    //! Gets the inclination angle along a certain direction at a position. (FP version.)
    virtual Ogre::Radian getInclination(const Ogre::Vector2 & position, const Ogre::Vector2 & direction) const = 0;

    //! Sees whether a point is blocked for air units.
    //virtual bool isBlockedForAirUnits(sim::Int x, sim::Int y) const = 0;

    //! Sees whether a point is blocked for ground units.
    virtual bool isBlockedForGroundUnits(sim::Int x, sim::Int y) const = 0;

    //! Sees whether a point is blocked for buildings.
    //virtual bool isBlockedForBuildings(sim::Int x, sim::Int y) const = 0;

    //! Finds a path between two points.
    virtual void findGroundUnitPath(const sim::Int2d & origin, const sim::Int2d & destination, PointList & path) const = 0;

    //! Need to initialize the path finder nodes after the world has been realized in ogre!
    virtual void initPathFinder() = 0;
    
    //! Finds a path for flying units...
    //virtual void findAirUnitPath(const sim::Int2d & origin, const sim::Int2d & destination, PointList & path) const = 0;
};

class LandscapeSpatialsImpl;

/**
    Represents the static elements of a scene. Should do the necessary scene management for
    static elements (loading and placing the heightmap and static models).
    
    Provides methods for accessing the spatial characteristics of the landscape
    through getLandscapeSpatials().

    A landscape is initialized from a landscape.cfg file.
    */
class Landscape {
friend class LandscapeSpatialsImpl;
    Ogre::TerrainSceneManager & sceneMan_;
    LandscapeSpatials::Pointer spatials_;

    void loadLandscape(const boost::property_tree::ptree & landscapeNode);
    void loadObject(const boost::property_tree::ptree & objectNode);
    static Ogre::Vector2 loadVec2(const boost::property_tree::ptree & vecNode);
    static Ogre::Vector3 loadVec3(const boost::property_tree::ptree & vecNode);
public:
    Landscape(const Ogre::String & filename, Ogre::SceneManager & scene);
    ~Landscape(); //should not remove any scene stuff, it's impossible to do without clearScene() called elsewhere anyway

    LandscapeSpatials & getSpatials() const; // TODO: Put back the const LandscapeSpatials. This is a bad hack to fix initialisation of PathFinder.
};

}; //namespace spelprog2

#endif //LANDSCAPE_HPP
